#include "simulated_uart.h"

#include "tim.h"
#include "usart.h"
#include "gpio.h"


#define BIT(a,n)      ((a >> n) & 0x01)

static inline void suart_stop(suart_t *suart)
{
	suart->tx_pin_set(PIN_HIGH);
	switch((int)suart->stop_bits)
	{
		case SUART_STOP_BITS_HALF:
			suart->delay_100ns(suart->bit_interval_100ns / 2);
		break;
		case SUART_STOP_BITS_ONE:
			suart->delay_100ns(suart->bit_interval_100ns);
		break;
		case SUART_STOP_BITS_ONE_AND_HALF:
			suart->delay_100ns(suart->bit_interval_100ns / 2 * 3);
		break;
		case SUART_STOP_BITS_TWO:
			suart->delay_100ns(suart->bit_interval_100ns * 2);
		break;
		default:
			break;
	}
}

static inline uint8_t count_byte_bit_is_1(uint8_t byte)
{
	return (BIT(byte, 0) + BIT(byte, 1) + BIT(byte, 2) + BIT(byte, 3) +
					BIT(byte, 4) + BIT(byte, 5) + BIT(byte, 6) + BIT(byte, 7));
}

static inline void suart_parity(suart_t *suart, uint8_t byte)
{
	switch((int)suart->parity)
	{
		case SUART_PARITY_NO:
		break;
		case SUART_PARITY_ODD:
			if (count_byte_bit_is_1(byte) % 2) {
				suart->tx_pin_set(PIN_LOW);
			}
			else {
				suart->tx_pin_set(PIN_HIGH);
			}
			suart->delay_100ns(suart->bit_interval_100ns);
		break;
		case SUART_PARITY_EVEN:
			if (count_byte_bit_is_1(byte) % 2) {
				suart->tx_pin_set(PIN_HIGH);
			}
			else {
				suart->tx_pin_set(PIN_LOW);
			}
			suart->delay_100ns(suart->bit_interval_100ns);
		break;
		case SUART_PARITY_SPACE:
			suart->tx_pin_set(PIN_LOW);
			suart->delay_100ns(suart->bit_interval_100ns);
		break;
		case SUART_PARITY_MARK:
			suart->tx_pin_set(PIN_HIGH);
			suart->delay_100ns(suart->bit_interval_100ns);
		break;
		default:
			break;
	}
}

static void suart_send_byte(suart_t *suart, uint8_t byte)
{
	if (!suart) {
		return ;
	}
	
	/* 起始位 */
	suart->tx_pin_set(PIN_LOW);
	suart->delay_100ns(suart->bit_interval_100ns);
	
	/* 数据位 */
	for (int i = 0; i < suart->data_bits; i++) {
		suart->tx_pin_set((byte >> i) & 0x01);
		suart->delay_100ns(suart->bit_interval_100ns);
	}
	
	/* 校验位 */
	suart_parity(suart, byte);
	
	/* 停止位 */
	suart_stop(suart);
}

int suart_init(suart_t *suart, uint8_t *buffer, uint32_t size, 
							void (*tx_pin_set)(bool high), 
							bool (*rx_pin_get)(),
							void (*delay_us)(uint32_t cnt),
							void (*recv_timer_ctrl)(bool start))
{
	if (!suart || !tx_pin_set || !rx_pin_get || !delay_us || !recv_timer_ctrl) {
		return SUART_ARGS_NULL;
	}
	
	suart->baudrate = SUART_BAUDRATE_115200;
	suart->data_bits = SUART_DATA_BITS_8;
	suart->parity = SUART_PARITY_NO;
	suart->stop_bits = SUART_STOP_BITS_ONE;
	
	suart->tx_pin_set = tx_pin_set;
	suart->rx_pin_get = rx_pin_get;
	suart->delay_100ns = delay_us;
	suart->recv_timer_ctrl = recv_timer_ctrl;
	
	suart->bit_interval_100ns = 1e7 / suart->baudrate; 
	
	suart->tx_pin_set(PIN_HIGH);
	
	suart->half_period_cnt = 0;
	suart->recv_byte = 0;
	suart->recv_bit_index = 0;
	suart->recv_running = false;
	
	ringbuffer_init(&suart->ringbuffer, buffer, size);
	
	return SUART_OK;
}

void suart_config(suart_t *suart, suart_baudrate_e baudrate,
									suart_data_bits_e data_bits,
									suart_parity_e parity,
									suart_stop_bits_e stop_bits)
{
	if (!suart) return ;
	suart->baudrate = baudrate;
	suart->data_bits = data_bits;
	suart->parity = parity;
	suart->stop_bits = stop_bits;
	
	suart->bit_interval_100ns = 1e7 / suart->baudrate; 
}
							
int suart_send_bytes(suart_t *suart, uint8_t *data, int len)
{
	for (int i = 0; i < len; i++) {
		suart_send_byte(suart, data[i]);
	}
	return SUART_OK;
}

int suart_receive_bytes(suart_t *suart, uint8_t *data, int len)
{
	return ringbuffer_pop(&suart->ringbuffer, data, len);
}

static uint32_t half_period_cnt = 0;
static uint8_t recv_byte = 0;
static uint8_t bit_index = 0;
static bool recv_start = false;

void suart_timer_int_handler(suart_t *suart)
{
	if (!suart) return ;
	
#if 1
	++suart->half_period_cnt;
	if (1 == suart->half_period_cnt) {
		return;
	}
	
	if (suart->recv_bit_index < 8 && suart->half_period_cnt % 2) {
		suart->recv_byte |= ((suart->rx_pin_get() & 0x01) << suart->recv_bit_index);
		++suart->recv_bit_index;
	}
	else {
		if (suart->half_period_cnt % 2 && suart->rx_pin_get() == PIN_HIGH) {
			suart->recv_timer_ctrl(TIMER_STOP);
			suart->recv_running = false;
			ringbuffer_push(&suart->ringbuffer, &suart->recv_byte, 1);
		}
	}
#else
		++half_period_cnt;
		if (1 == half_period_cnt) {
			return;
		}
		
		if (bit_index < 8 && (half_period_cnt % 2) ) {
			recv_byte |= ((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9) & 0x01) << bit_index);
			++bit_index;
		}
		else {
			if (half_period_cnt % 2 && HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9) == GPIO_PIN_SET) {
				HAL_TIM_Base_Stop_IT(&htim3);
				recv_start = false;
				extern ringbuffer_t ringbuffer;
				ringbuffer_push(&ringbuffer, &recv_byte, 1);
			}
		}
#endif
}

void suart_rx_pin_int_handler(suart_t *suart)
{
	if (!suart) return ;
#if 1
	if (!suart->recv_running) {
		suart->recv_running = true;
		suart->recv_byte = 0;
		suart->half_period_cnt = 0;
		suart->recv_bit_index = 0;
		suart->recv_timer_ctrl(TIMER_START);
	}
#else 
	if (!recv_start) {
		recv_start = true;
		recv_byte = 0;
		half_period_cnt = 0;
		bit_index = 0;
		HAL_TIM_Base_Start_IT(&htim3);
	}
	
#endif
}


